
#include <BFile>
#include <BOpenGL>
#include <BKeyEvent>
#include <BMouseEvent>
#include <BStyleDocument>
#include <BGraphicItem>

#include "IGlobal.h"
#include "member_BGraphicItem.h"
#include "member_BGraphicWidget.h"
#include "member_BStyle.h"
#include "member_BObject.h"

using namespace BWE;

#define member					(*(member_BGraphicItem*)_ptr)
#define member_allocate()		_ptr = new member_BGraphicItem(this)
#define member_release()		delete (member_BGraphicItem*)_ptr

BGraphicItem::BGraphicItem(BGraphicItem* parent)
{
	member_allocate();
	setParent(parent);
}
BGraphicItem::BGraphicItem(const BString& name, BGraphicItem* parent) : BObject(name)
{
	member_allocate();
	setParent(parent);
}
BGraphicItem::BGraphicItem(BWidget* widget, BGraphicItem* parent)
{
	member_allocate();
	setParent(parent);
	setWidget(widget);
}
BGraphicItem::BGraphicItem(const BGraphicItem& other)
{
	member_allocate();
	this->copy(&other);
}
BGraphicItem::~BGraphicItem()
{
	member_release();
}

void BGraphicItem::copy(const BGraphicItem* other)
{
	object_member(this)->name = object_member(other)->name;

	member.visible = item_member(other)->visible;
	member.focusable = item_member(other)->focusable;

	member.tips = item_member(other)->tips;
	member.pos = item_member(other)->pos;
	member.size = item_member(other)->size;
	member.rotate = item_member(other)->rotate;
	member.border = item_member(other)->border;
	member.perch = item_member(other)->perch;
	member.margin = item_member(other)->margin;
	member.originAlign = item_member(other)->originAlign;

	if (BWidget* widget = item_member(other)->widget)
	{
		member.widget = widget->clone();
	}

	for (int i = 0; i < item_member(other)->children.size(); i++)
	{
		BGraphicItem* item = item_member(other)->children[i];
		BGraphicItem* child = item->clone();
		member.children.append(child);
	}
}
BGraphicItem* BGraphicItem::clone() const
{
	return new BGraphicItem(*this);
}

void BGraphicItem::setVisible(bool visible)
{
	if (member.visible != visible)
	{
		member.visible = visible;
		if (member.visible)
			this->emit(Signal_Show, true);
		else
			this->emit(Signal_Hide, false);
		if (member.graphic)
		{
			member.graphic->fresh();
		}
	}
}
bool BGraphicItem::visible() const
{
	return member.visible;
}

void BGraphicItem::setSelected(bool selected)
{
	if (member.graphic && member.selected != selected)
	{
		member.graphic->setItemSelected(this, selected);
	}
}
bool BGraphicItem::selected() const
{
	return member.graphic && member.selected;
}

bool BGraphicItem::setOriginAlign(Align originAlign)
{
	if (member.originAlign != originAlign)
	{
		member.originAlign = originAlign;
		this->emit(Signal_OriginAligned, originAlign);
		this->dirty();
		return true;
	}
	return false;
}
Align BGraphicItem::originAlign() const
{
	return member.originAlign;
}

void BGraphicItem::setBackground(BByte r, BByte g, BByte b, BByte a)
{
	setBackground(BColor(r, g, b, a));
}
void BGraphicItem::setBackground(const BColor& background)
{
	if (member.background != background)
	{
		member.background = background;
		if (member.graphic)
			member.graphic->fresh();
	}
}
const BColor& BGraphicItem::background() const
{
	return member.background;
}

void BGraphicItem::setForeground(BByte r, BByte g, BByte b, BByte a)
{
	setForeground(BColor(r, g, b, a));
}
void BGraphicItem::setForeground(const BColor& foreground)
{
	if (member.foreground != foreground)
	{
		member.foreground = foreground;
		if (member.graphic)
			member.graphic->fresh();
	}
}
const BColor& BGraphicItem::foreground() const
{
	return member.foreground;
}

bool BGraphicItem::setWidget(BWidget* widget)
{
	if (member.widget != widget)
	{
		if (member.graphic && member.widget)
		{
			member.graphic->removeChild(member.widget);
			member.widget = 0;
		}
		member.widget = widget;
		if (member.graphic && member.widget)
		{
			member.graphic->addChild(member.widget);
			member.widget->setFloating(false);
			member.dirtyCell();
		}
		return true;
	}
	return false;
}
const BWidget* BGraphicItem::widget() const
{
	return member.widget;
}
BWidget* BGraphicItem::widget()
{
	return member.widget;
}

void BGraphicItem::setFont(const BString& family, int size)
{
	BFont* font = new BFont(family, size);
	setFont(font);
}
void BGraphicItem::setFont(BFont* font)
{
	if (member.style.empty())
	{
		member.style = new BStyle();
	}
	member.style->setFont(font);
	member.dirtyStyle = true;
	this->fresh();
}
const BFont* BGraphicItem::font() const
{
	if (member.realStyle)
		return member.realStyle->font();
	if (member.graphic)
		member.graphic->realStyle()->font();
	return app_style->font();
}
BFont* BGraphicItem::font()
{
	if (member.realStyle)
		return member.realStyle->font();
	if (member.graphic)
		member.graphic->realFont();
	return 0;
}

bool BGraphicItem::setStyle(BStyle* style)
{
	if (member.style != style)
	{
		member.style = style;
		member.dirtyStyle = true;
		this->fresh();
	}
	return true;
}
const BStyle* BGraphicItem::style() const
{
	if (member.realStyle)
		return member.realStyle;
	if (member.graphic)
		member.graphic->realStyle();
	return app_style;
}
BStyle* BGraphicItem::style()
{
	if (member.realStyle)
		return member.realStyle;
	if (member.graphic)
		member.graphic->realStyle();
	return app_style;
}

const BStyle* BGraphicItem::realStyle() const
{
	if (member.realStyle)
		return member.realStyle;
	return app_style;
}
void BGraphicItem::clearStyle()
{
	if (member.style)
	{
		member.style = 0;
		member.dirtyStyle = true;
		this->fresh();
	}
	if (member.realStyle)
	{
		member.realStyle = 0;
		member.dirtyStyle = true;
		this->fresh();
	}
}

void BGraphicItem::setRadius(const BSizef& radius, PartFlag part)
{
	bool changed = false;
	if (member.round.empty())
	{
		member.round = new IRound();
		changed = true;
	}
	if (part & Part_Left && part & Part_Top)
	{
		if (member.round->radiusLeftTop != radius)
		{
			member.round->radiusLeftTop = radius;
			changed = true;
		}
	}
	if (part & Part_Left && part & Part_Bottom)
	{
		if (member.round->radiusLeftBottom != radius)
		{
			member.round->radiusLeftBottom = radius;
			changed = true;
		}
	}
	if (part & Part_Right && part & Part_Top)
	{
		if (member.round->radiusRightTop != radius)
		{
			member.round->radiusRightTop = radius;
			changed = true;
		}
	}
	if (part & Part_Right && part & Part_Bottom)
	{
		if (member.round->radiusRightBottom != radius)
		{
			member.round->radiusRightBottom = radius;
			changed = true;
		}
	}
	if (changed)
	{
		member.dirty = true;
		member.dirtyCell();
		this->emit(Signal_Changed);
		this->fresh();
	}
}
void BGraphicItem::setRadius(const BSizef& leftTop, const BSizef& rightTop, const BSizef& rightBottom, const BSizef& leftBottom)
{
	if (member.round.empty() && leftTop.empty() && rightTop.empty() && rightBottom.empty() && leftBottom.empty())
		return;
	bool changed = false;
	if (member.round.empty())
	{
		member.round = new IRound();
		changed = true;
	}
	if (member.round->radiusLeftTop != leftTop)
	{
		member.round->radiusLeftTop = leftTop;
		changed = true;
	}
	if (member.round->radiusRightTop != rightTop)
	{
		member.round->radiusRightTop = rightTop;
		changed = true;
	}
	if (member.round->radiusRightBottom != rightBottom)
	{
		member.round->radiusRightBottom = rightBottom;
		changed = true;
	}
	if (member.round->radiusLeftBottom != leftBottom)
	{
		member.round->radiusLeftBottom = leftBottom;
		changed = true;
	}
	if (changed)
	{
		member.dirty = true;
		member.dirtyCell();
		this->emit(Signal_Changed);
		this->fresh();
	}
}
BSizef BGraphicItem::radius(PartFlag part)
{
	if (member.round)
	{
		if (part == Part_LeftTop)
			return member.round->radiusLeftTop;
		if (part == Part_RightTop)
			return member.round->radiusRightTop;
		if (part == Part_RightBottom)
			return member.round->radiusRightBottom;
		if (part == Part_LeftBottom)
			return member.round->radiusLeftBottom;
		return member.round->radiusLeftTop;
	}
	return BSize();
}

void BGraphicItem::setBorder(float border)
{
	if (member.border != border)
	{
		member.border = border;
		member.freshRects();
	}
}
float BGraphicItem::border() const
{
	return member.border;
}

void BGraphicItem::setPerch(float left, float top, float right, float bottom)
{
	setPerch(BPerchf(left, top, right, bottom));
}
void BGraphicItem::setPerch(const BPerchf& perch)
{
	if (member.perch != perch)
	{
		member.perch = perch;
		member.freshRects();
	}
}
const BPerchf& BGraphicItem::perch() const
{
	return member.perch;
}

void BGraphicItem::setPerch(Part part, float value)
{
	BPerchf perch = member.perch;
	if (part & Part_Top)
		perch.top() = value;
	if (part & Part_Left)
		perch.left() = value;
	if (part & Part_Right)
		perch.right() = value;
	if (part & Part_Bottom)
		perch.bottom() = value;
	this->setPerch(perch);
}
float BGraphicItem::perch(Part part) const
{
	switch (part)
	{
	case Part_Top:
		return member.perch.top();
	case Part_Left:
		return member.perch.left();
	case Part_Right:
		return member.perch.right();
	case Part_Bottom:
		return member.perch.bottom();
	default:
		return -1;
	}
}

bool BGraphicItem::setMargin(float left, float top, float right, float bottom)
{
	return setMargin(BMarginf(left, top, right, bottom));
}
bool BGraphicItem::setMargin(const BMarginf& margin)
{
	if (member.margin != margin)
	{
		member.margin = margin;
		member.freshRects();
		return true;
	}
	return false;
}
const BMarginf& BGraphicItem::margin() const
{
	return member.margin;
}

bool BGraphicItem::setMargin(Part part, float value)
{
	BMarginf margin = member.margin;
	if (part & Part_Left)
		margin.left() = value;
	if (part & Part_Top)
		margin.top() = value;
	if (part & Part_Right)
		margin.right() = value;
	if (part & Part_Bottom)
		margin.bottom() = value;
	return this->setMargin(margin);
}
float BGraphicItem::margin(Part part) const
{
	switch (part)
	{
	case Part_Left:
		return member.margin.left();
	case Part_Top:
		return member.margin.top();
	case Part_Right:
		return member.margin.right();
	case Part_Bottom:
		return member.margin.bottom();
	default:
		return -1.0f;
	}
}

bool BGraphicItem::move(float ox, float oy)
{
	return this->setPos(member.pos + BPointf(ox, oy));
}
bool BGraphicItem::move(const BPointf& offset)
{
	return this->setPos(member.pos + offset);
}

bool BGraphicItem::setPos(float x, float y)
{
	return setPos(BPointf(x, y));
}
bool BGraphicItem::setPos(const BPointf& pos)
{
	if (member.pos != pos)
	{
		member.pos = pos;
		member.dirty = true;
		BEvent moveEvent(Event_Move);
		moveEvent.setValue(member.pos);
		member.event(moveEvent);
		this->fresh();
		return true;
	}
	return false;
}
const BPointf& BGraphicItem::pos() const
{
	return member.pos;
}

bool BGraphicItem::setRotate(float rotate)
{
	if (member.rotate != rotate)
	{
		member.rotate = rotate;
		member.dirty = true;
		BEvent moveEvent(Event_Rotate);
		moveEvent.setValue(member.pos);
		member.event(moveEvent);
		this->fresh();
		return true;
	}
	return false;
}
float BGraphicItem::rotate() const
{
	return member.rotate;
}

bool BGraphicItem::setWidth(float width)
{
	return setSize(BSizef(width, member.size.height()));
}
float BGraphicItem::width() const
{
	return member.size.width();
}

bool BGraphicItem::setHeight(float height)
{
	return setSize(BSizef(member.size.width(), height));
}
float BGraphicItem::height() const
{
	return member.size.height();
}

bool BGraphicItem::setSize(float width, float height)
{
	return setSize(BSizef(width, height));
}
bool BGraphicItem::setSize(const BSizef& size)
{
	if (member.size != size)
	{
		member.size = size;
		member.dirty = true;
		BEvent resizeEvent(Event_Resize);
		resizeEvent.setValue(member.pos);
		member.event(resizeEvent);
		this->fresh();
		return true;
	}
	return false;
}
const BSizef& BGraphicItem::size() const
{
	return member.size;
}

void BGraphicItem::setRect(float x, float y, float width, float height)
{
	setPos(BPointf(x, y));
	setSize(BSizef(width, height));
}
void BGraphicItem::setRect(const BRectf& rect)
{
	setPos(rect.pos());
	setSize(rect.size());
}
const BRectf& BGraphicItem::rect() const
{
	if (member.dirty)
	{
		this->flush();
	}
	return member.rect;
}
BRectf BGraphicItem::rect(Part part) const
{
	switch (part)
	{
	case Part_None:
		return member.rectBack;
	case Part_Top:
		return member.rectTop;
	case Part_Left:
		return member.rectLeft;
	case Part_Right:
		return member.rectRight;
	case Part_Bottom:
		return member.rectBottom;
	case Part_Center:
		return member.rectCenter;
	case Part_LeftTop:
		return member.rectLeftTop;
	case Part_LeftBottom:
		return member.rectLeftBottom;
	case Part_RightTop:
		return member.rectRightTop;
	case Part_RightBottom:
		return member.rectRightBottom;
	default:
		return BRectf();
	}
}
const BRectf& BGraphicItem::area() const
{
	return member.area;
}

BSizef BGraphicItem::centerSize() const
{
	return member.rectCenter.size();
}
const BRectf& BGraphicItem::centerRect() const
{
	return member.rectCenter;
}

void BGraphicItem::setAbsolutePos(const BPointf& absolutePos)
{
	BPointf pos = absolutePos - this->absolutePos();
	setPos(pos);
}
void BGraphicItem::setAbsolutePos(float absoluteX, float absoluteY)
{
	BPointf abPos(absoluteX, absoluteY);
	setAbsolutePos(abPos);
}
BPointf BGraphicItem::absolutePos() const
{
	BPointf abPos = member.pos;
	const BGraphicItem* parent = member.parent;
	while (parent)
	{
		abPos += item_member(parent)->pos;
		parent = item_member(parent)->parent;
	}
	return abPos;
}
BRectf BGraphicItem::absoluteRect() const
{
	BRectf abRect = this->rect();
	const BGraphicItem* parent = member.parent;
	while (parent)
	{
		abRect += item_member(parent)->pos;
		parent = item_member(parent)->parent;
	}
	return abRect;
}

BPointf BGraphicItem::globalPos() const
{
	BPointf pos = absolutePos();
	if (member.graphic)
	{
		pos += member.graphic->offset();
	}
	return pos;
}
BRectf BGraphicItem::globalRect() const
{
	BRectf rect = absoluteRect();
	if (member.graphic)
	{
		rect += member.graphic->offset();
	}
	return rect;
}

BPointf BGraphicItem::mapTo(const BGraphicItem* item, const BPointf& point) const
{
	if (!item)
		return BPointf();

	BPointf upPoint = point;
	const BGraphicItem* uw = this;
	while (uw)
	{
		if (uw == item)
			return upPoint;
		upPoint += uw->pos();
		uw = uw->parent();
	}

	BPointf downPoint = point;
	const BGraphicItem* dw = item;
	while (dw)
	{
		if (dw == this)
			return downPoint;
		downPoint -= dw->pos();
		dw = dw->parent();
	}

	return upPoint - item->absolutePos();
}
BPointf BGraphicItem::mapFrom(const BGraphicItem* item, const BPointf& point) const
{
	if (!item)
		return BPointf();

	BPointf upPoint = point;
	const BGraphicItem* uw = item;
	while (uw)
	{
		if (uw == this)
			return upPoint;
		upPoint += uw->pos();
		uw = uw->parent();
	}

	BPointf downPoint = point;
	const BGraphicItem* dw = this;
	while (dw)
	{
		if (dw == item)
			return downPoint;
		downPoint -= dw->pos();
		dw = dw->parent();
	}

	return upPoint - this->absolutePos();
}

BRectf BGraphicItem::mapTo(const BGraphicItem* item, const BRectf& rect) const
{
	if (!item)
		return BRectf();

	BRectf upRect = rect;
	const BGraphicItem* uw = this;
	while (uw)
	{
		if (uw == item)
			return upRect;
		upRect += uw->pos();
		uw = uw->parent();
	}

	BRectf downRect = rect;
	const BGraphicItem* dw = item;
	while (dw)
	{
		if (dw == this)
			return downRect;
		downRect -= dw->pos();
		dw = dw->parent();
	}

	return upRect - item->absolutePos();
}
BRectf BGraphicItem::mapFrom(const BGraphicItem* item, const BRectf& rect) const
{
	if (!item)
		return BRectf();

	BRectf upRect = rect;
	const BGraphicItem* up = item;
	while (up)
	{
		if (up == this)
			return upRect;
		upRect += up->pos();
		up = up->parent();
	}

	BRectf downRect = rect;
	const BGraphicItem* down = this;
	while (down)
	{
		if (down == item)
			return downRect;
		downRect -= down->pos();
		down = down->parent();
	}

	return upRect - this->absolutePos();
}

BSizef BGraphicItem::preferSize(float cwidth, float cheight) const
{
	return preferSize(BSizef(cwidth, cheight));
}
BSizef BGraphicItem::preferSize(const BSizef& csize) const
{
	BSizef centerSize = csize;
	const BPerchf& p = member.perch;
	const BMarginf& m = member.margin;
	float b = member.border;
	float pwidth = b + p.left() + m.left() + m.right() + p.right() + b + centerSize.width();
	float pheight = b + p.top() + m.top() + m.bottom() + p.bottom() + b + centerSize.height();
	return BSizef(pwidth, pheight);
}
BSizef BGraphicItem::preferSize(PartFlag part) const
{
	if (part == Part_All)
		return preferSize(BSizef());

	BSizef leftSize;
	BSizef topSize;
	BSizef rightSize;
	BSizef bottomSize;

	BSizef centerSize = 0;

	switch (part)
	{
	case Part_Left:
		return leftSize;
	case Part_Right:
		return rightSize;
	case Part_Top:
		return topSize;
	case Part_Bottom:
		return bottomSize;
	case Part_LeftTop:
		return BSizef(leftSize.width(), topSize.height());
	case Part_RightTop:
		return BSizef(rightSize.width(), topSize.height());
	case Part_LeftBottom:
		return BSizef(leftSize.width(), bottomSize.height());
	case Part_RightBottom:
		return BSizef(rightSize.width(), bottomSize.height());
	case Part_Center:
		return centerSize;
	}
	return BSizef(0, 0);
}
BSizef BGraphicItem::shellSize() const
{
	float b = member.border;
	const BMarginf& m = member.margin;
	float swidth = b + m.left() + m.right() + b;
	float sheight = b + m.top() + m.bottom() + b;
	return BSizef(swidth, sheight);
}

void BGraphicItem::dirty() const
{
	if (!member.dirty)
	{
		member.dirty = true;
		if (BGraphicWidget* graphic = member.graphic)
		{
			member.graphic->fresh();
			graphic_member(graphic)->dirty = true;
		}
		this->emit(Signal_Dirty);
	}
}
bool BGraphicItem::flush() const
{
	for (int i = 0; i < member.children.size(); i++)
	{
		member.children[i]->flush();
	}
	if (member.dirty)
	{
		member.dirty = false;
		this->refresh(member.rectBack);
		member.rect = member.rectBack + member.pos;
		member.freshRects();
		this->fresh();
	}
	return false;
}
void BGraphicItem::refresh(BRectf& rect) const
{
	rect.reset();
	if (member.originAlign)
	{
		if (member.originAlign & Align_Right)
			rect.left() = -member.size.width();
		if (member.originAlign & Align_Bottom)
			rect.top() = -member.size.height();
		if (member.originAlign & Align_HCenter)
			rect.left() = -member.size.width() / 2;
		if (member.originAlign & Align_VCenter)
			rect.top() = -member.size.height() / 2;
	}
	rect.setSize(member.size);
}
bool BGraphicItem::catchPoint(const BPointf& point) const
{
	return member.rectBack.contain(point);
}

bool BGraphicItem::query(const BString& text, BValue& value) const
{
	return BObject::query(text, value);
}

void BGraphicItem::setParent(BGraphicItem* parent)
{
	if (member.parent != parent)
	{
		BHolder<BGraphicItem> holder;
		if (member.parent)
		{
			holder = this;
			member.parent->removeChild(this);
		}
		if (parent)
		{
			parent->addChild(this);
			holder = 0;
		}
	}
}
BGraphicItem* BGraphicItem::parent()
{
	return member.parent;
}
const BGraphicItem* BGraphicItem::parent() const
{
	return member.parent;
}

bool BGraphicItem::addChild(BGraphicItem* child)
{
	if (!child)
		return false;
	if (child == this)
		return false;
	if (member.children.contain(child))
		return true;
	member.children.append(child);
	if (item_member(child)->graphic)
		item_member(child)->graphic->removeItem(child);
	if (item_member(child)->parent)
		item_member(child)->parent->removeChild(child);
	item_member(child)->parent = this;
	item_member(child)->attach(member.graphic);
	if (member.area.contain(child->area()))
		member.raiseDirty();
	object_member(child)->emit(Signal_ParentChanged, BValue(this, true));
	member.raiseSignal(Signal_ItemInserted, child);
	this->fresh();
	return true;
}
BGraphicItem* BGraphicItem::addChild(const BString& name)
{
	BGraphicItem* item = new BGraphicItem(name);
	if (addChild(item))
		return item;
	return 0;
}

bool BGraphicItem::insertChild(int pos, BGraphicItem* child)
{
	if (!child)
		return false;
	if (child == this)
		return false;
	int index = member.children.find(child);
	if (index < member.children.size())
	{
		member.children.move(index, pos);
		this->fresh();
		return true;
	}
	member.children.insert(pos, child);
	if (item_member(child)->parent)
		item_member(child)->parent->removeChild(child);
	item_member(child)->parent = this;
	if (item_member(child)->graphic)
		item_member(child)->graphic->removeItem(child);
	item_member(child)->attach(member.graphic);
	if (member.area.contain(child->area()))
		member.raiseDirty();
	object_member(child)->emit(Signal_ParentChanged, BValue(this, true));
	member.raiseSignal(Signal_ItemInserted, child);
	this->fresh();
	return true;
}
BGraphicItem* BGraphicItem::insertChild(int pos, const BString& name)
{
	BGraphicItem* item = new BGraphicItem(name);
	if (insertChild(pos, item))
		return item;
	return 0;
}

bool BGraphicItem::removeChild(BGraphicItem* child)
{
	if (!child)
		return false;
	if (child == this)
		return false;
	if (!member.children.contain(child))
		return false;
	if (member.graphic)
	{
		graphic_member(member.graphic)->selectedItems.remove(child);
	}
	BHolder<BGraphicItem> holder(child);
	item_member(child)->parent = 0;
	item_member(child)->detach(member.graphic);
	member.children.remove(child);
	if (member.area.contain(child->area()))
		member.raiseDirty();
	object_member(child)->emit(Signal_ParentChanged);
	member.raiseSignal(Signal_ItemRemoved, child);
	this->fresh();
	return true;
}
bool BGraphicItem::removeChild(const BString& name)
{
	if (BGraphicItem* child = this->child(name))
	{
		return removeChild(child);
	}
	return false;
}
bool BGraphicItem::removeChild(int pos)
{
	if (member.children.check(pos))
	{
		BGraphicItem* item = member.children[pos];
		item_member(item)->graphic = 0;
		item_member(item)->parent = 0;
		member.children.remove(pos);
		member.raiseSignal(Signal_Changed);
		return true;
	}
	return false;
}
void BGraphicItem::clearChildren()
{
	while (BGraphicItem* child = member.children.last())
	{
		this->removeChild(child);
	}
}

int BGraphicItem::childCount() const
{
	return member.children.size();
}
BGraphicItem* BGraphicItem::child(int index)
{
	return member.children[index];
}
const BGraphicItem* BGraphicItem::child(int index) const
{
	return member.children[index];
}

BGraphicItem* BGraphicItem::child(const BString& name)
{
	for (int i = 0; i < member.children.size(); i++)
	{
		if (member.children[i]->name() == name)
			return member.children[i];
	}
	return 0;
}
const BGraphicItem* BGraphicItem::child(const BString& name) const
{
	for (int i = 0; i < member.children.size(); i++)
	{
		if (member.children[i]->name() == name)
			return member.children[i];
	}
	return 0;
}

BGraphicItem* BGraphicItem::childOfAsset(const BValue& asset)
{
	for (int i = 0; i < member.children.size(); i++)
	{
		BGraphicItem* child = member.children[i];
		if (child->asset() == asset)
			return child;
	}
	return 0;
}
const BGraphicItem* BGraphicItem::childOfAsset(const BValue& asset) const
{
	for (int i = 0; i < member.children.size(); i++)
	{
		BGraphicItem* child = member.children[i];
		if (child->asset() == asset)
			return child;
	}
	return 0;
}

BGraphicItem* BGraphicItem::findByName(const BString& name)
{
	if (this->name() == name)
		return this;
	for (int i = 0; i < member.children.size(); i++)
	{
		BGraphicItem* child = member.children[i];
		BGraphicItem* result = child->findByName(name);
		if (result)
			return result;
	}
	return 0;
}
const BGraphicItem* BGraphicItem::findByName(const BString& name) const
{
	if (this->name() == name)
		return this;
	for (int i = 0; i < member.children.size(); i++)
	{
		const BGraphicItem* child = member.children[i];
		const BGraphicItem* result = child->findByName(name);
		if (result)
			return result;
	}
	return 0;
}

BGraphicItem* BGraphicItem::findByAsset(const BValue& asset)
{
	if (asset.empty())
		return 0;
	if (this->asset() == asset)
		return this;
	for (int i = 0; i < member.children.size(); i++)
	{
		BGraphicItem* child = member.children[i];
		BGraphicItem* item = child->findByAsset(asset);
		if (item)
			return item;
	}
	return 0;
}
const BGraphicItem* BGraphicItem::findByAsset(const BValue& asset) const
{
	if (asset.empty())
		return 0;
	if (this->asset() == asset)
		return this;
	for (int i = 0; i < member.children.size(); i++)
	{
		const BGraphicItem* child = member.children[i];
		const BGraphicItem* item = child->findByAsset(asset);
		if (item)
			return item;
	}
	return 0;
}

BGraphicItem* BGraphicItem::create(const BString& path)
{
	int end = path.find('/');
	if (end == path.size())
	{
		BGraphicItem* item = this->child(path);
		if (item == 0)
			item = this->addChild(path);
		return item;
	}
	BString text;
	path.substr(text, 0, end);
	BGraphicItem* item = this->child(text);
	if (item == 0)
		item = this->addChild(text);
	int pos = end + 1;
	while (item && pos < path.size())
	{
		end = path.find('/', pos);
		path.substr(text, pos, end);
		BGraphicItem* child = item->child(text);
		if (child == 0)
			child = item->addChild(text);
		item = child;
		pos = end + 1;
	}
	return item;
}

BGraphicItem* BGraphicItem::locate(const BString& path)
{
	if (path.empty())
		return this;
	BStringArray textlst = path.split('/');
	BGraphicItem* item = this->child(textlst.first());
	textlst.remove(0);
	while (item && textlst.size())
	{
		const BString& text = textlst.first();
		item = item->child(text);
		textlst.remove(0);
	}
	return item;
}
const BGraphicItem* BGraphicItem::locate(const BString& path) const
{
	if (path.empty())
		return this;
	BStringArray textlst = path.split('/');
	const BGraphicItem* item = this->child(textlst.first());
	textlst.remove(0);
	while (item && textlst.size())
	{
		const BString& text = textlst.first();
		item = item->child(text);
		textlst.remove(0);
	}
	return item;
}

BGraphicWidget* BGraphicItem::graphicWidget()
{
	return member.graphic;
}
const BGraphicWidget* BGraphicItem::graphicWidget() const
{
	return member.graphic;
}

BGraphicItem* BGraphicItem::root()
{
	BGraphicItem* item = this;
	while (item_member(item)->parent)
		item = item_member(item)->parent;
	return item;
}
const BGraphicItem* BGraphicItem::root() const
{
	const BGraphicItem* item = this;
	while (item_member(item)->parent)
		item = item_member(item)->parent;
	return item;
}

BGraphicItem* BGraphicItem::prev()
{
	if (member.graphic)
	{
		int index = this->index();
		if (member.parent)
		{
			return member.parent->child(index - 1);
		}
		return member.graphic->item(index - 1);
	}
	return 0;
}
const BGraphicItem* BGraphicItem::prev() const
{
	if (member.graphic)
	{
		int index = this->index();
		if (member.parent)
		{
			return member.parent->child(index - 1);
		}
		return member.graphic->item(index - 1);
	}
	return 0;
}

BGraphicItem* BGraphicItem::next()
{
	if (member.graphic)
	{
		int index = this->index();
		if (member.parent)
		{
			return member.parent->child(index + 1);
		}
		return member.graphic->item(index + 1);
	}
	return 0;
}
const BGraphicItem* BGraphicItem::next() const
{
	if (member.graphic)
	{
		int index = this->index();
		if (member.parent)
		{
			return member.parent->child(index + 1);
		}
		return member.graphic->item(index + 1);
	}
	return 0;
}

bool BGraphicItem::contain(const BGraphicItem* item) const
{
	if (!item)
		return false;
	for (int i = 0; i < member.children.size(); i++)
	{
		if (member.children[i] == item)
			return true;
	}
	return false;
}
bool BGraphicItem::above(const BGraphicItem* item) const
{
	if (!item)
		return false;
	BGraphicItem* parent = member.parent;
	while (parent)
	{
		if (parent == this)
			return true;
		parent = item_member(parent)->parent;
	}
	return false;
}
bool BGraphicItem::under(const BGraphicItem* item) const
{
	BGraphicItem* parent = member.parent;
	while (parent)
	{
		if (parent == item)
			return true;
		parent = item_member(parent)->parent;
	}
	return false;
}

bool BGraphicItem::setIndex(int index)
{
	if (member.parent)
	{
		BGraphicItemHolderArray& children = item_member(member.parent)->children;
		int pos = children.find(this);
		if (children.move(pos, index))
		{
			member.raiseSignal(Signal_OrderChanged);
			this->fresh();
			return true;
		}
	}
	else
	{
		BGraphicItemHolderArray& items = graphic_member(member.graphic)->items;
		int pos = items.find(this);
		if (items.move(pos, index))
		{
			member.raiseSignal(Signal_OrderChanged);
			this->fresh();
			return true;
		}
	}
	return false;
}
int BGraphicItem::index() const
{
	if (BGraphicItem* parent = member.parent)
	{
		BArray<BGraphicItemHolder>& children = item_member(parent)->children;
		return children.find(this);
	}
	if (member.graphic)
	{
		return member.graphic->itemIndex(this);
	}
	return -1;
}
int BGraphicItem::level() const
{
	int level = 0;
	const BGraphicItem* parent = member.parent;
	while (parent)
	{
		level++;
		parent = parent->parent();
	}
	return level;
}

bool BGraphicItem::raise()
{
	if (member.parent)
	{
		BGraphicItemHolderArray& children = item_member(member.parent)->children;
		int pos = children.find(this);
		if (children.move(pos, children.size() - 1))
		{
			member.raiseSignal(Signal_OrderChanged);
			this->fresh();
			return true;
		}
	}
	if (member.graphic)
	{
		BGraphicItemHolderArray& items = graphic_member(member.graphic)->items;
		int pos = items.find(this);
		if (items.move(pos, items.size() - 1))
		{
			member.raiseSignal(Signal_OrderChanged);
			this->fresh();
			return true;
		}
	}
	return false;
}
bool BGraphicItem::lower()
{
	if (member.parent)
	{
		BGraphicItemHolderArray& children = item_member(member.parent)->children;
		int pos = children.find(this);
		if (children.move(pos, 0))
		{
			member.raiseSignal(Signal_OrderChanged);
			this->fresh();
			return true;
		}
	}
	else
	{
		BGraphicItemHolderArray& items = graphic_member(member.graphic)->items;
		int pos = items.find(this);
		if (items.move(pos, 0))
		{
			member.raiseSignal(Signal_OrderChanged);
			this->fresh();
			return true;
		}
	}
	return false;
}

bool BGraphicItem::hovered() const
{
	return member.hovered;
}
bool BGraphicItem::fresh() const
{
	if (!member.refresh)
	{
		member.refresh = true;
		BGraphicItem* upper = member.parent;
		while (upper)
		{
			item_member(upper)->refresh = true;
			upper = item_member(upper)->parent;
		}
		if (BGraphicWidget* graphic = member.graphic)
		{
			graphic_member(graphic)->dirty = true;
			graphic->fresh();
		}
		return true;
	}
	return false;
}

BString BGraphicItem::path(const char* split) const
{
	BString text = this->name();
	const BGraphicItem* item = this->parent();
	while (item)
	{
		text.prepend(split);
		text.prepend(item->name());
		item = item->parent();
	}
	return text;
}
BString BGraphicItem::path(const BString& split) const
{
	BString text = this->name();
	const BGraphicItem* item = this->parent();
	while (item)
	{
		text.prepend(split);
		text.prepend(item->name());
		item = item->parent();
	}
	return text;
}

BString BGraphicItem::pathTo(const BGraphicItem* parent, const char* split) const
{
	if (this == parent)
		return BString();
	if (parent && !this->under(parent))
		return BString();
	BString text = this->name();
	const BGraphicItem* item = this->parent();
	while (item && item != parent)
	{
		text.prepend(split);
		text.prepend(item->name());
		item = item->parent();
	}
	return text;
}
BString BGraphicItem::pathTo(const BGraphicItem* parent, const BString& split) const
{
	if (this == parent)
		return BString();
	if (parent && !this->under(parent))
		return BString();
	BString text = this->name();
	const BGraphicItem* item = this->parent();
	while (item && item != parent)
	{
		text.prepend(split);
		text.prepend(item->name());
		item = item->parent();
	}
	return text;
}

void BGraphicItem::drawBackground(BPainter& painter, State state)
{
	if (!state)
		state = painter.state();
	if (member.hovered)
		state |= State_Hovered;
	else if (member.selected)
		state |= State_Selected;

	float border = member.border;
	BRectf backRect = member.rectBack;
	backRect.left() += border;
	backRect.right() -= border;
	backRect.top() += border;
	backRect.bottom() -= border;
	if (const BImage* image = painter.image(Image_Background, state))
	{
		float left = member.rectCenter.left() - backRect.left();
		float top = member.rectCenter.top() - backRect.top();
		float right = backRect.right() - member.rectCenter.right();
		float bottom = backRect.bottom() - member.rectCenter.bottom();
		painter.drawImage(backRect, image, BMarginf(left, top, right, bottom));
		return;
	}
	if (painter.setColor(member.background) || painter.setColor(Color_Background, state))
	{
		if (IRound* round = member.round)
		{
			glEnable(GL_MULTISAMPLE);
			glBegin(GL_TRIANGLE_FAN);
			for (int i = 0; i < round->backgroundPoints.size(); i++)
			{
				const BPointf& p = round->backgroundPoints[i];
				glVertex2f(p.x(), p.y());
			}
			glEnd();
			glDisable(GL_MULTISAMPLE);
		}
		else
		{
			painter.fillRect(backRect);
		}
	}
}
void BGraphicItem::drawForeground(BPainter& painter, State state)
{
	if (!state)
		state = painter.state();
	if (member.hovered)
		state |= State_Hovered;
	else if (member.selected)
		state |= State_Selected;

	if (painter.setColor(member.foreground) || painter.setColor(Color_Foreground, state))
	{
		BRecti foreRect = member.rectCenter;
		if (IRound* round = member.round)
		{
			glEnable(GL_MULTISAMPLE);
			if (const BImage* image = painter.image(Image_Foreground, state))
			{
				painter.bind(image);
				glBegin(GL_TRIANGLE_FAN);
				int pointSize = round->centerPoints.size();
				for (int i = 0; i < pointSize; i++)
				{
					const BPointf& p = round->centerPoints[i];
					float tx = (p.x() - foreRect.x()) / foreRect.width();
					float ty = (foreRect.bottom() - p.y()) / foreRect.height();
					glTexCoord2f(tx, ty);
					glVertex2f(p.x(), p.y());
				}
				glEnd();
				painter.unbind();
			}
			else
			{
				glBegin(GL_TRIANGLE_FAN);
				for (int i = 0; i < round->centerPoints.size(); i++)
				{
					const BPointf& p = round->centerPoints[i];
					glVertex2f(p.x(), p.y());
				}
				glEnd();
			}
			glDisable(GL_MULTISAMPLE);
		}
		else
		{
			if (const BImage* image = painter.image(Image_Foreground, state))
				painter.drawImage(foreRect, image);
			else
				painter.fillRect(foreRect);
		}
	}
}
void BGraphicItem::drawPerch(BPainter& painter, State state)
{
	const BPerchf& perch = this->perch();
	if (perch == BPerchf())
		return;

	if (!state)
		state = painter.state();
	if (member.hovered)
		state |= State_Hovered;
	else if (member.selected)
		state |= State_Selected;

	if (const BImage* image = painter.image(Image_Perch, state))
	{
		painter.bind(image);
		float b = member.border;
		float left = perch.left();
		float top = perch.top();
		float right = perch.right();
		float bottom = perch.bottom();
		float w = member.rect.width() - b - b;
		float h = member.rect.height() - b - b;
		float tw = (float)image->width();
		float th = (float)image->height();
		painter.fillRect(member.rectLeft, BRectf(0, top, left, th - top - bottom));
		painter.fillRect(member.rectTop, BRectf(left, 0, tw - left - right, top));
		painter.fillRect(member.rectRight, BRectf(tw - left, top, right, th - top - bottom));
		painter.fillRect(member.rectBottom, BRectf(left, th - bottom, tw - left - right, bottom));
		painter.fillRect(member.rectLeftTop, BRectf(0, 0, left, top));
		painter.fillRect(member.rectRightTop, BRectf(tw - right, 0, right, top));
		painter.fillRect(member.rectLeftBottom, BRectf(0, th - bottom, left, bottom));
		painter.fillRect(member.rectRightBottom, BRectf(tw - right, th - bottom, right, bottom));
		painter.unbind();
		return;
	}
	if (painter.setColor(Color_Perch, state))
	{
		if (IRound* round = member.round)
		{
			glEnable(GL_MULTISAMPLE);
			painter.fillTriangles(round->perchPoints);
			glDisable(GL_MULTISAMPLE);
		}
		else
		{
			painter.fillRect(member.rectLeft);
			painter.fillRect(member.rectTop);
			painter.fillRect(member.rectRight);
			painter.fillRect(member.rectBottom);
			painter.fillRect(member.rectLeftTop);
			painter.fillRect(member.rectLeftBottom);
			painter.fillRect(member.rectRightTop);
			painter.fillRect(member.rectRightBottom);
		}
	}
}
void BGraphicItem::drawMargin(BPainter& painter, State state)
{
	if (member.margin == BMarginf())
		return;

	if (!state)
		state = painter.state();
	if (member.hovered)
		state |= State_Hovered;
	else if (member.selected)
		state |= State_Selected;

	const BRectf& crect = member.rectCenter;
	float w = member.rect.width();
	float h = member.rect.height();

	float left = (float)member.margin.left();
	float top = (float)member.margin.top();
	float right = (float)member.margin.right();
	float bottom = (float)member.margin.bottom();

	BRectf rectLeft(crect.left() - left, crect.top(), left, crect.height());
	BRectf rectTop(crect.left(), crect.top() - top, crect.width(), top);
	BRectf rectRight(crect.right(), crect.top(), right, crect.height());
	BRectf rectBottom(crect.left(), crect.bottom(), crect.width(), bottom);

	BRectf rectLetfTop(crect.left() - left, crect.top() - top, left, top);
	BRectf rectRightTop(crect.right(), crect.top() - top, right, top);
	BRectf rectLeftBottom(crect.left() - left, crect.bottom(), left, bottom);
	BRectf rectRightBottom(crect.right(), crect.bottom(), right, bottom);

	if (const BImage* image = painter.image(Image_Margin, state))
	{
		painter.bind(image);
		float w = member.rect.width();
		float h = member.rect.height();
		int tw = image->width();
		int th = image->height();
		painter.fillRect(rectLeft, BRectf(0, top, left, th - top - bottom));
		painter.fillRect(rectTop, BRectf(left, 0, tw - left - right, top));
		painter.fillRect(rectRight, BRectf(tw - right, top, right, th - top - bottom));
		painter.fillRect(rectBottom, BRectf(left, th - bottom, tw - left - right, bottom));
		painter.fillRect(rectLetfTop, BRectf(0, 0, left, top));
		painter.fillRect(rectRightTop, BRectf(tw - right, 0, right, top));
		painter.fillRect(rectLeftBottom, BRectf(0, th - bottom, left, bottom));
		painter.fillRect(rectRightBottom, BRectf(tw - right, th - bottom, right, bottom));
		painter.unbind();
		return;
	}
	if (painter.setColor(Color_Margin, state))
	{
		if (IRound* round = member.round)
		{
			glEnable(GL_MULTISAMPLE);
			painter.fillTriangles(round->marginPoints);
			glDisable(GL_MULTISAMPLE);
		}
		else
		{
			painter.fillRect(rectLeft);
			painter.fillRect(rectTop);
			painter.fillRect(rectRight);
			painter.fillRect(rectBottom);

			painter.fillRect(rectLetfTop);
			painter.fillRect(rectRightTop);
			painter.fillRect(rectLeftBottom);
			painter.fillRect(rectRightBottom);
		}
	}
}
void BGraphicItem::drawBorder(BPainter& painter, State state)
{
	if (member.border < 1)
		return;

	if (!state)
		state = painter.state();
	if (member.hovered)
		state |= State_Hovered;
	else if (member.selected)
		state |= State_Selected;

	float b = member.border;
	const BRectf& rect = member.rectBack;
	float w = member.rect.width();
	float h = member.rect.height();
	BRectf rectLeft(rect.left(), rect.top() + b, b, h - b - b);
	BRectf rectTop(rect.left() + b, rect.top(), w - b - b, b);
	BRectf rectRight(rect.right() - b, rect.top() + b, b, h - b - b);
	BRectf rectBottom(rect.left() + b, rect.bottom() - b, w - b - b, b);

	BRectf rectLeftTop(rect.left(), rect.top(), b, b);
	BRectf rectRightTop(rect.right() - b, rect.top(), b, b);
	BRectf rectLeftBottom(rect.left(), rect.bottom() - b, b, b);
	BRectf rectRightBottom(rect.right() - b, rect.bottom() - b, b, b);

	if (const BImage* image = painter.image(Image_Border, state))
	{
		painter.bind(image);
		int tw = image->width();
		int th = image->height();
		painter.fillRect(rectLeft, BRectf(0, b, b, th - b - b));
		painter.fillRect(rectTop, BRectf(b, 0, tw - b - b, b));
		painter.fillRect(rectRight, BRectf(tw - b, b, b, th - b - b));
		painter.fillRect(rectBottom, BRectf(b, th - b, tw - b - b, b));
		painter.fillRect(rectLeftTop, BRectf(0, 0, b, b));
		painter.fillRect(rectRightTop, BRectf(tw - b, 0, b, b));
		painter.fillRect(rectLeftBottom, BRectf(0, th - b, b, b));
		painter.fillRect(rectRightBottom, BRectf(tw - b, th - b, b, b));
		painter.unbind();
		return;
	}
	if (painter.setColor(Color_Border, state))
	{
		if (IRound* round = member.round)
		{
			glEnable(GL_MULTISAMPLE);
			painter.fillTriangles(round->borderPoints);
			glDisable(GL_MULTISAMPLE);
		}
		else
		{
			painter.fillRect(rectLeft);
			painter.fillRect(rectTop);
			painter.fillRect(rectRight);
			painter.fillRect(rectBottom);
			painter.fillRect(rectLeftTop);
			painter.fillRect(rectRightTop);
			painter.fillRect(rectLeftBottom);
			painter.fillRect(rectRightBottom);
		}
	}
}
void BGraphicItem::drawTitle(BPainter& painter, State state)
{
	BRectf rectTitle = member.rectTitle;
	if (rectTitle.empty())
		return;

	if (!state)
		state = painter.state();
	if (member.hovered)
		state |= State_Hovered;
	else if (member.selected)
		state |= State_Selected;

	if (IRound* round = member.round)
	{
		glEnable(GL_MULTISAMPLE);
		if (const BImage* image = painter.image(Image_Title, state))
		{
			painter.bind(image);
			glBegin(GL_TRIANGLES);
			int pointSize = round->centerPoints.size();
			for (int i = 0; i < pointSize; i += 3)
			{
				const BPointf& p = round->centerPoints[i];
				float tx = (p.x() - rectTitle.x()) / rectTitle.width();
				float ty = (rectTitle.bottom() - p.y()) / rectTitle.height();
				glTexCoord2f(tx, ty);
				glVertex2f(p.x(), p.y());
			}
			glEnd();
			painter.unbind();
		}
		else if (painter.setColor(Color_Title, state))
		{
			painter.fillTriangles(round->titlePoints);
		}
		glDisable(GL_MULTISAMPLE);
	}
	else
	{
		if (const BImage* image = painter.image(Image_Title, state))
			painter.drawImage(rectTitle, image);
		else if (painter.setColor(Color_Title, state))
			painter.fillRect(rectTitle);
	}

}

void BGraphicItem::paint(BPainter& painter)
{
	drawBackground(painter);
	drawForeground(painter);
	drawTitle(painter);
	drawMargin(painter);
	drawPerch(painter);
	drawBorder(painter);
}

void BGraphicItem::moveEvent(const BEvent& event)
{
	this->emit(Signal_Moved, member.pos);
}
void BGraphicItem::rotateEvent(const BEvent& event)
{
	this->emit(Signal_Rotated, member.rotate);
}
void BGraphicItem::resizeEvent(const BEvent& event)
{
	this->emit(Signal_Resized, member.rect.size());
}
void BGraphicItem::updateEvent(const BEvent& event)
{

}

void BGraphicItem::styleEvent(const BEvent& event)
{
	this->emit(Signal_Styled, event.value());
}
void BGraphicItem::freshEvent(const BEvent& event)
{
	if (member.dirty)
	{
		member.dirty = false;
		this->refresh(member.rectBack);
		member.rect = member.rectBack + member.pos;
		member.freshRects();
		this->fresh();
	}
	this->emit(Signal_Freshed, event.value());
}

void BGraphicItem::focusEvent(const BEvent& event)
{
	this->emit(Signal_Focused, member.focused);
}
void BGraphicItem::keyPressEvent(const BKeyEvent& keyEvent)
{
	this->emit(Signal_KeyPress, keyEvent.key());
}
void BGraphicItem::keyReleaseEvent(const BKeyEvent& keyEvent)
{
	this->emit(Signal_KeyRelease, keyEvent.key());
}

void BGraphicItem::mouseEnterEvent(const BMouseEvent& mouseEvent)
{
	this->emit(Signal_MouseEnter, mouseEvent.pos());
}
void BGraphicItem::mouseLeaveEvent(const BMouseEvent& mouseEvent)
{
	this->emit(Signal_MouseLeave, mouseEvent.pos());
}

void BGraphicItem::mousePressEvent(const BMouseEvent& mouseEvent)
{

}
void BGraphicItem::mouseReleaseEvent(const BMouseEvent& mouseEvent)
{

}
void BGraphicItem::mouseMoveEvent(const BMouseEvent& mouseEvent)
{

}
void BGraphicItem::mouseWheelEvent(const BMouseEvent& mouseEvent)
{

}

void BGraphicItem::mouseClickEvent(const BMouseEvent& mouseEvent)
{

}
void BGraphicItem::mouseDoubleClickEvent(const BMouseEvent& mouseEvent)
{

}

void BGraphicItem::dragEnterEvent(const BMouseEvent& mouseEvent)
{

}
void BGraphicItem::dragLeaveEvent(const BMouseEvent& mouseEvent)
{

}
void BGraphicItem::dragMoveEvent(const BMouseEvent& mouseEvent)
{

}
void BGraphicItem::dragDropEvent(const BMouseEvent& mouseEvent)
{

}
